package com.aloha.springframework.beans.factory.support;

import com.aloha.springframework.beans.BeansException;
import com.aloha.springframework.beans.factory.DisposableBean;
import com.aloha.springframework.beans.factory.ObjectFactory;
import com.aloha.springframework.beans.factory.config.SingletonBeanRegistry;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author DaiZhiHeng
 * @description 单例Bean的注册中心
 * @date 2023/6/27 21:55
 */
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    protected static final Object NULL_OBJECT = new Object();

    /**
     * 存放所有已经完成初始化操作的单例Bean的单例池(一级缓存)
     */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    /**
     * 为避免循环依赖在创建完对象还未填充属性就放入这个缓存池中(二级缓存)
     */
    protected final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();

    /**
     * 解决代理对象循环依赖的 三级缓存池
     */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

    /**
     * 存放所有实现了DisposableBean接口的对象的池
     */
    private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap<>();

    @Override
    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = singletonObjects.get(beanName);
        // 一级缓存中没有
        if (singletonObject == null) {
            // 去二级缓存中找
            singletonObject = earlySingletonObjects.get(beanName);
            // 二级缓存中没有，并且可以访问三级缓存
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = singletonFactories.get(beanName); // 三级缓存
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    // 放入二级缓存
                    earlySingletonObjects.put(beanName, singletonObject);
                    singletonFactories.remove(beanName);
                }
            }
        }
        return singletonObject;
    }

    /**
     * 向单例池中添加单例对象
     */
    public void registerSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);
        earlySingletonObjects.remove(beanName);
        singletonFactories.remove(beanName);
    }

    public void registerDisposableBean(String beanName, DisposableBean disposableBean) {
        disposableBeans.put(beanName, disposableBean);
    }

    /**
     * 添加工厂对象
     */
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        singletonFactories.put(beanName, singletonFactory);
    }

    /**
     * 执行销毁方法
     */
    public void destroySingletons() {
        // 获取beanName
        String[] disposableBeanNames = disposableBeans.keySet().toArray(new String[0]);
        // 按照添加的逆序执行销毁方法
        for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
            String beanName = disposableBeanNames[i];
            DisposableBean disposableBean = disposableBeans.remove(beanName);
            try {
                disposableBean.destroy();
            } catch (Exception e) {
                throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
            }
        }
    }
}
